<!-- 文件上传组件 -->
<template>
  <div class="component-file-upload">
    <el-upload
      class="upload-demo"
      ref="uploadRef"
      :headers="headers"
      :action="uploadAddress"
      :limit="fileNum"
      :before-upload="beforeFileUpload"
      :on-change="handleFileChange"
      :on-exceed="handleExceed"
      :file-list="fileList"
      :on-error="handleFileError"
      :on-remove="clearFileList"
      :on-success="handleFileSuccess"
      :before-remove="handleBeforeRemove"
      :accept="acceptString"
      method="post"
      list-type="text"
      drag
      show-file-list
      multiple
      auto-upload
      with-credentials
    >
      <el-icon class="el-icon--upload"><upload-filled /></el-icon>
      <div class="el-upload__text">拖拽文件上传/ <em>点击上传</em></div>
      <template #tip>
        <div class="el-upload__tip">
          单个文件大小不超过 5Mb,音频/视频只能上传一个文件
        </div>
      </template>
    </el-upload>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, defineEmits, onUnmounted } from "vue";
import { ElMessage } from "element-plus";
import type { UploadInstance, UploadProps } from "element-plus";
import { useUserInfoStore } from "@/store/userInfoStore";
import { deleteOssFile } from "@/api/page/home.js";

const userInfoToken = useUserInfoStore();

const fileUrl = ref("");
const emit = defineEmits(["file"]);
const timeoutRef = ref<NodeJS.Timeout | null>(null);

const props = defineProps({
  // 上传地址
  uploadAddress: {
    type: String,
    default: "/api/file/upload",
  },
  // 文件路径
  fileUrl: {
    type: [String, Array], // 允许两种类型
    default: "",
    validator(value) {
      return typeof value === "string" || Array.isArray(value);
    },
  },
  // 大小限制(MB)
  fileSize: {
    type: Number,
    default: 5,
  },
  // 是否显示提示
  isShowTip: {
    type: Boolean,
    default: true,
  },
  //  文件个数
  fileNum: {
    type: Number,
    default: 3,
  },
  //   文件类型
  fileType: {
    type: Array,
    default: () => [
      "png",
      "jpg",
      "jpeg",
      "mp4",
      "mp3",
      "webp",
      "gif",
      "webm",
      "wav",
    ],
  },
});

// 请求头
const headers = computed(() => {
  let header = {
    satoken: `${userInfoToken.tokenInfo}`,
  };
  return header;
});

const successfulFiles = ref<FileData[]>([]);
interface FileData {
  size: string;
  url: string;
}

const uploadRef = ref<UploadInstance>();
const audioVideoData = ref([]);

onUnmounted(() => {
  if (timeoutRef.value) {
    clearTimeout(timeoutRef.value);
  }
  // 清除audioVideoData
  audioVideoData.value = [];
});

// 文件列表
const fileList = ref<UploadUserFile[]>([]);

// 文件类型
const acceptString = computed(() => {
  // 1. 确保每个文件类型前有 '.' 并过滤空值
  const validTypes = props.fileType
    .map((type) => `.${type.trim()}`)
    .filter((type) => type.length > 1 && !type.includes(" "));

  // 2. 使用逗号连接（自动过滤空字符串）
  return validTypes.join(",");
});
// 文件上传前
const beforeFileUpload: UploadProps["beforeUpload"] = (rawFile) => {
  console.log("beforeFileUpload--headers", fileList.value);

  // 检查audioVideoData,判断数量是否超过1
  if (audioVideoData.value.length >= 1) {
    // 清除前一个文件
    let fileName = audioVideoData.value.shift();
    // 根据文件名，删除存储数据
    let imgData: string[] = [];
    imgData.push(fileName);
    deleteOssFile(imgData);
  }
};

// 文件状态改变时的钩子，添加文件、上传成功和上传失败时都会被调用
const handleFileChange: UploadProps["onChange"] = (uploadFile, uploadFiles) => {
  // 检查文件类型
  let formatFlag = false;
  let rawFile = uploadFile.raw!;
  // 判断文件类型
  if (props.fileType.length) {
    let fileExtension = "";
    if (rawFile.name.lastIndexOf(".") > -1) {
      fileExtension = rawFile.name.slice(rawFile.name.lastIndexOf(".") + 1);
    }
    formatFlag = props.fileType.some((type) => {
      if (fileExtension && fileExtension == type) {
        return true;
      }
    });
  }
  if (!formatFlag) {
    ElMessage.error(
      `文件格式不正确, 请上传${props.fileType.join("/")}图片格式文件!`
    );
    uploadRef.value!.clearFiles();
  }
  // 判断文件是否为视频或音频
  const isVideoOrAudio = checkFileType(uploadFile);
  // 只能上传一个视频或音频
  if (isVideoOrAudio) {
    // 替换原来的文件
    fileList.value = [uploadFile];
    console.log("文件替换后的列表：", fileList.value);
  }
};

// 当超出限制时，执行的钩子函数
const handleExceed: UploadProps["onExceed"] = (files) => {
  // 当文件数量超过时，会阻止上传
  ElMessage.error(`上传文件个数不能超过${props.fileNum}个!`);
};

// 文件上传失败时的钩子
const handleFileError: UploadProps["onError"] = (error, uploadFile) => {
  ElMessage.error("文件上传失败!");
  // 清除文件列表
  uploadRef.value!.clearFiles();
  // 清除定时器和重置状态
  if (timeoutRef.value) {
    clearTimeout(timeoutRef.value);
  }
  timeoutRef.value = null;
};

// 文件列表移除文件时的钩子
const clearFileList: UploadProps["onRemove"] = (uploadFile, uploadFiles) => {
  // 文件移除时，获取该文件的文件名
  let fileName = uploadFile.response?.filePath || "";
  if (fileName) {
    // 获取文件名
    fileName = fileName.split("/").pop();
    console.log("fileName:", fileName);
    // 将当前文件名变为数组
    let imgData = [];
    imgData.push(fileName);
    // 根据文件名，删除存储数据
    deleteOssFile(imgData);
    resetTimeout();
  }
};

// 文件移除之前触发
const handleBeforeRemove: UploadProps["beforeRemove"] = (
  uploadFile,
  UploadFiles
) => {
  // 返回true允许删除，或根据业务逻辑返回Promise<boolean>
  return true;
};

// 文件上传成功时的钩子
const handleFileSuccess: UploadProps["onSuccess"] = (
  response,
  uploadFile,
  UploadFiles
) => {
  console.log("文件上传成功：", UploadFiles);
  // 判断当前上传的文件是否为视频或音频
  if (checkFileType(uploadFile)) {
    // 如果是视频或音频，将返回的文件地址添加到audioVideoData数组中
    const fileName = uploadFile.response?.filePath?.split("/").pop() || "";
    if (fileName) audioVideoData.value.push(fileName);
  }

  // 添加当前成功文件
  const newItem = {
    size: (uploadFile.raw!.size / 1024).toFixed(2),
    url: uploadFile.response?.filePath || "",
  };

  const urlSet = new Set(successfulFiles.value.map((item) => item.url));
  if (!urlSet.has(newItem.url)) {
    successfulFiles.value.push(newItem);
  }

  // 清除之前的定时器
  resetTimeout();

  // 只有当所有文件都上传成功时才设置定时器
  if (successfulFiles.value.length === UploadFiles.length) {
    console.log(`所有${UploadFiles.length}个文件已上传成功，开始4秒计时`);
    timeoutRef.value = setTimeout(() => {
      console.log("触发文件上传完成事件");
      emit("file", [...successfulFiles.value]); 
      uploadRef.value?.clearFiles();
      audioVideoData.value = [];
      successfulFiles.value = [];
    }, 4000);
  }
};

//统一重置定时器的函数
function resetTimeout() {
  if (timeoutRef.value) {
    clearTimeout(timeoutRef.value);
    timeoutRef.value = null;
  }
}

// 判断文件是否为视频或音频
function checkFileType(file: UploadFile) {
  if (!file.raw) return false;
  const fileName = file.raw.name;
  const ext = fileName.slice(fileName.lastIndexOf(".") + 1).toLowerCase();
  return [
    "mp4",
    "mp3",
    "webm",
    "wav",
    "avi",
    "mov",
    "mpeg",
    "wmv",
    "rmvb",
    "flv",
    "mkv",
    "flac",
    "alac",
    "aac",
    "wma",
    "ogg",
  ].includes(ext);
}
</script>

<style lang="scss" scoped></style>
